package gpstools.matching;

import gpstools.Location;
import gpstools.Polyline;
import gpstools.TrainingPoint;
import gpstools.calc.Calculator;
import gpstools.track.TrackPoint;
import gpstools.track.TrackPoint.Builder;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import mskruch.gps.Point;
import mskruch.gps.PointFactory;
import mskruch.gps.Position;

public class LegacyTrackFinder implements TrackFinder {
    private static final int DEFAULT_DISTANCE_BETWEEN_CHECKPOINTS = 640;

    private mskruch.gps.matching.legacy.TrackFinder tf;
    private Set<Long> roundedTimes = new TreeSet<Long>();

    @Override
    public List<? extends TrainingPoint> next() {
        Point[] found = tf.next();
        if (found != null) {
            long roundedTime = Math.round((double) found[found.length - 1].getTime() / 10000);
            if (roundedTimes.contains(roundedTime)) {
                return this.next();
            } else {
                roundedTimes.add(roundedTime);

                List<TrainingPoint> tp = new ArrayList<TrainingPoint>();
                for (Point point : found) {
                    gpstools.Point location = new gpstools.Point(point.getLatitude(), point.getLongitude(),
                            point.getElevation());
                    Builder builder = TrackPoint.builder(location).time(point.getTime())
                            .heartRate(point.getHeartRate()).cadence(point.getCadence());
                    TrackPoint p = builder.build();
                    tp.add(p);
                }
                return tp;
            }
        } else {
            return null;
        }
    }

    @Override
    public void setPattern(List<? extends Location> pattern) {
        Location first = pattern.get(0);
        Location last = pattern.get(pattern.size() - 1);
        boolean loop = first.equals(last);

        int checks = (int) (Calculator.distance(pattern) / DEFAULT_DISTANCE_BETWEEN_CHECKPOINTS);
        checks = Integer.valueOf(Math.max(checks, 2));
        Location[] array = pattern.toArray(new Location[pattern.size()]);
        List<Location> checkPoints = new Polyline(array).findCheckpoints(checks);

        Position f = PointFactory.newPosition(first);
        Position l = PointFactory.newPosition(last);

        Position[] cp = new Position[checkPoints.size()];

        int i = 0;
        for (Location location : checkPoints) {
            cp[i++] = PointFactory.newPosition(location);
        }

        if (loop) {
            tf = new mskruch.gps.matching.legacy.TrackFinder(f, cp);
        } else {
            tf = new mskruch.gps.matching.legacy.TrackFinder(f, l, cp);
        }
    }

    @Override
    public void setSource(List<? extends TrainingPoint> source) {
        Point[] s = new Point[source.size()];
        int i = 0;
        for (TrainingPoint point : source) {
            s[i++] = PointFactory.newPoint(point);
        }
        tf.setSource(s);
        roundedTimes.clear();
    }

    @Override
    public List<? extends Location> getMissedLocations() {
        return null;
    }

}
